package com.gec.system.filter;

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.gec.model.system.SysOperLog;
import com.gec.model.vo.LoginVo;
import com.gec.system.common.Result;
import com.gec.system.common.ResultCodeEnum;
import com.gec.system.config.Constant;
import com.gec.system.custom.CustomUser;
import com.gec.system.service.SysLoginLogService;
import com.gec.system.service.SysOperLogService;
import com.gec.system.util.IpUtil;
import com.gec.system.util.JwtHelper;
import com.gec.system.util.ResponseUtil;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;

import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**登录的过滤器*/
public class TokenLoginFilter extends UsernamePasswordAuthenticationFilter {
    private RedisTemplate redisTemplate;
    private SysLoginLogService sysLoginLogService;
    private AuthenticationManager authenticationManager;

    /**创建一个TokenLoginFilter对象，配置为Spring Security的身份验证过滤器链的一部分
     * 用于处理用户进行登录时发送的请求：身份验证*/
    public TokenLoginFilter(AuthenticationManager authenticationManager, RedisTemplate redisTemplate,SysLoginLogService sysLoginLogService){
        this.authenticationManager=authenticationManager;
        //设置请求方法不严格限定为post请求
        this.setPostOnly(false);
        //new AntPathRequestMatcher()作为请求匹配器,指定url,请求来进行身份验证
        // 用户尝试登录的时候调用身份验证机制
        this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(Constant.LONGIN_URL,"POST"));
        this.redisTemplate=redisTemplate;
        this.sysLoginLogService=sysLoginLogService;
    }

    /**用户认证
     * 拿到账号密码调用验证管理器的验证方法*/
    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException {
        try {
            LoginVo loginVo = new ObjectMapper().readValue(request.getInputStream(), LoginVo.class);
            System.out.println("账号为 " + loginVo.getUsername());
            System.out.println("密码为 " + loginVo.getPassword());
            return  authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(loginVo.getUsername(),loginVo.getPassword()));
        } catch (IOException e) {
            e.printStackTrace();
        }
        return  authenticationManager.authenticate(new UsernamePasswordAuthenticationToken(null,null));
    }
    /**验证成功*/
    @Override
    protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain, Authentication auth) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        //获取用户详细信息，并将其转换为CustomUser对象
        CustomUser user= (CustomUser) auth.getPrincipal();
        //创建一个新的令牌,传入id和用户名作为令牌的内容
        String token= JwtHelper.createToken(user.getSysUser().getId()+"",user.getSysUser().getUsername());
        System.out.println("token为 " + token);
        //保存权限数据
        redisTemplate.opsForValue().set(user.getUsername(), JSON.toJSONString(user.getAuthorities()));
        //记录用户登录日志 并且将结果输出到控制台里面 存储到数据库中
        sysLoginLogService.recordLoginLog(user.getUsername(),1, IpUtil.getIpAddress(request),"登录成功");
        //使用map返回给客户端
        Map<String,Object> map=new HashMap<>();
        map.put("token",token);
        System.out.println("map为：" + map);
        //使用ResponseUtil.out封装响应结果
        ResponseUtil.out(response, Result.ok(map));
    }
    /**验证失败*/
    @Override
    protected void unsuccessfulAuthentication(HttpServletRequest request, HttpServletResponse response, AuthenticationException e) throws IOException, ServletException {
        response.setContentType("application/json;charset=UTF-8");
        if(e.getCause() instanceof RuntimeException){
            ResponseUtil.out(response,Result.build(null,204,e.getMessage()));
        }else{
            ResponseUtil.out(response,Result.build(null, ResultCodeEnum.LOGIN_MOBLE_ERROR));
        }
    }
}
